#pragma once
#pragma pack(1)

struct socket;
/*
     *      1 ----- ICMP
     *      2 ----- IGMP
     *      6 ----- TCP
     *      17----- UDP
     *      88----- IGRP
     *      89----- OSPF
*/
#define CONFIG_PATH "./config/"
#define CONFIG_FILE CONFIG_PATH"config"
#define DATA_BUF_SIZE 1024
#define BLOCK_POINT while(1);

#define IP_VERSION 4
#define IP_LEN_V4  4
#define IPV4_LEN IP_LEN_V4
#define IP_NORM_HDR_LEN 20
#define IP_TTL64      64
#define WORD_SIZE  4
/*   In Ether header   */
#define PROTO_IP    0x0800

/*   In IP header   */
#define PROTO_ICMP  1
#define PROTO_UDP   17

#define WORD_SIZE  4
#define IP_HDR(raw) ((struct ip_hdr*)((char*)raw + 14))
#define UDP_HDR(IP_H) ((struct udp_hdr*)((char*)IP_H + IP_H->hdr_len*WORD_SIZE))

#define DEBUG_NET   1

typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;

/**
 * @brief ether header
 * length: 6 + 6 + 2 = 14Bytes
 */
struct eth_hdr {
#define MAC_LEN 6
    uint8_t dst[MAC_LEN];
    uint8_t src[MAC_LEN];
    uint16_t type;
}__attribute__((packed));

/**
 * @brief IP header
 *  length: 4 + 4 + 4 + 4 + 4 = 20Bytes
 * 
 *  MTU : MAX TRANSFORM UNIT once
 *        if total_len > MTU then split
 * 
 */
struct ip_hdr {
    uint8_t hdr_len:4,  // ipv4: 4     ipv6: 6
            version:4;  // header length : hdr_len * word(4) Bytes
    /**
     * @brief type of service
     * |0-1-2|----|3|----------|4|------------ |5|------|6-7|
     * priority  delayed   throughput       reliable    resolved
     * 优先级       延时        吞吐量          可靠性       保留
     */
    uint8_t tos;
    uint16_t total_len; // ip package total length

    uint16_t id;        // 
    uint16_t flags;     // flags = 0 + MF + DF + offset(13)
    /**
     * MF:   0 - 最后一个分片
     *       1 - 还有分片
     * DF:   0 - 允许分片
     *       1 - 禁止分片
     * 
     * 00100000 00000000
     */

    /**
     * @brief 
     * TTL: packet 每次经过一个路由器转发将 TTL 减一
     *      减为零时丢包，并发送一个 ICMP 包回给发送方
     * PROTO: 
     *      1 ----- ICMP
     *      2 ----- IGMP
     *      6 ----- TCP
     *      17----- UDP
     *      88----- IGRP
     *      89----- OSPF
     * CHECK: 
     *      check计算分为两种，下面分别解释两种计算方法
     *      send ---- rcv
     * 
     *      send calc:
     *              1. 清零 check
     *              2. 网络字节序下IP头部每 2byte 相加求和
     *              3. 溢出值再末尾求和取反
     * 
     *      rcv checK:
     *              1. 网络字节序下IP头部每 2byte 相加求和
     *              2. 溢出值再末尾求和取反
     *              3. 结果为0 则正确， 反之则错误
     */
    uint8_t ttl;        // if ttl == 0 then drop
    uint8_t proto;      // type of proto (udp / tcp / icmp)
    uint16_t check;     // check sum

    uint8_t ip_src[IP_LEN_V4];
    uint8_t ip_dst[IP_LEN_V4];
}__attribute__((packed));

/*********************************
 *  连接
 *********************************/

/**
 * @brief 层间头部包操作
 */
struct pkt_operations {
    void  (*creat_hdr)(void *data);
    void* (*destroy_hdr)(void *pkt);
    void  (*print)(void *hdr, struct socket *socket);
};
/**
 * @brief 网络进程: 此处的进程可以是同一台设备，也可以是不同设备
 */
struct net_proc {
    uint32_t ip;
    uint16_t port;
};

/**
 * @brief socket
 * 表示两个进程的连接
 */
#define SOCKET_DEBUG 0x01
struct socket {
    int fd_out;
    uint8_t proto;
    uint8_t flag;
    struct net_proc src, dst;
    struct pkt_operations *tl_ops, *nl_ops, *dl_ops;
};